home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / Ang261Lib.lha / src / recall.c < prev    next >
C/C++ Source or Header  |  1994-10-22  |  25KB  |  910 lines

  1. /*
  2.  * recall.c: print out monster memory info            -CJS- 
  3.  *
  4.  * Copyright (c) 1989 James E. Wilson, Christopher J. Stuart 
  5.  *
  6.  * This software may be copied and distributed for educational, research, and
  7.  * not for profit purposes provided that this copyright and statement are
  8.  * included in all such copies. 
  9.  */
  10.  
  11. #include "constant.h"
  12. #include "config.h"
  13. #include "monster.h"
  14. #include "types.h"
  15. #include "externs.h"
  16.  
  17. #include <stdio.h>
  18.  
  19. #ifndef NO_LINT_ARGS
  20. #ifdef __STDC__
  21. static void roff(const char *);
  22. #else
  23. static void         roff();
  24. #endif
  25. #endif
  26.  
  27. static const char  *desc_atype[] = {
  28.                     "do something undefined",
  29.                     "attack",
  30.                     "weaken",
  31.                     "confuse",
  32.                     "terrify",
  33.                     "burn",
  34.                     "shoot acid",
  35.                     "freeze",
  36.                     "electrify",
  37.                     "corrode",
  38.                     "blind",
  39.                     "paralyse",
  40.                     "steal money",
  41.                     "steal things",
  42.                     "poison",
  43.                     "reduce dexterity",
  44.                     "reduce constitution",
  45.                     "drain intelligence",
  46.                     "drain wisdom",
  47.                     "lower experience",
  48.                     "call for help",
  49.                     "disenchant",
  50.                     "eat your food",
  51.                     "absorb light",
  52.                     "absorb charges",
  53.                     "reduce all stats"};
  54. static const char  *desc_amethod[] = {
  55.                       "make an undefined advance",
  56.                       "hit",
  57.                       "bite",
  58.                       "claw",
  59.                       "sting",
  60.                       "touch",
  61.                       "kick",
  62.                       "gaze",
  63.                       "breathe",
  64.                       "spit",
  65.                       "wail",
  66.                       "embrace",
  67.                       "crawl on you",
  68.                       "release spores",
  69.                       "beg",
  70.                       "slime you",
  71.                       "crush",
  72.                       "trample",
  73.                       "drool",
  74.                       "insult",
  75.                       "butt",
  76.                       "charge",
  77.                       "engulf",
  78.                       "moan"
  79. };
  80.  
  81. static const char  *desc_howmuch[] = {
  82.                       " not at all",
  83.                       " a bit",
  84.                       "",
  85.                       " quite",
  86.                       " very",
  87.                       " most",
  88.                       " highly",
  89.                       " extremely"};
  90.  
  91. static const char  *desc_move[] = {
  92.                    "move invisibly",
  93.                    "open doors",
  94.                    "pass through walls",
  95.                    "kill weaker creatures",
  96.                    "pick up objects",
  97.                    "breed explosively"};
  98.  
  99. static const char  *desc_spell[] = {
  100.                     "1",
  101.                     "2",
  102.                     "4",
  103.                     "8",    /* 1+2+4+8=0xF = CS_FREQ...
  104.                          * freaky huh? */
  105.                     "teleport short distances",
  106.                     "teleport long distances",
  107.                     "teleport %s prey",
  108.                     "cause light wounds",
  109.                     "cause serious wounds",
  110.                     "paralyse %s prey",
  111.                     "induce blindness",
  112.                     "confuse",
  113.                     "terrify",
  114.                     "summon a monster",
  115.                     "summon the undead",
  116.                     "slow %s prey",
  117.                     "drain mana",
  118.                     "summon demonkind",
  119.                     "summon dragonkind",
  120.                     "lightning",    /* breaths 1 */
  121.                     "poison gases",
  122.                     "acid",
  123.                     "frost",
  124.                     "fire",    /* end */
  125.                     "cast fire bolts",
  126.                     "cast frost bolts",
  127.                     "cast acid bolts",
  128.                     "cast magic missiles",
  129.                     "cause critical wounds",
  130.                     "cast fire balls",
  131.                     "cast frost balls",
  132.                     "cast mana bolts",
  133.                     "chaos",    /* breaths2 */
  134.                     "shards",
  135.                     "sound",
  136.                     "confusion",
  137.                     "disenchantment",
  138.                     "nether",    /* end of part1 */
  139.                     "cast lightning bolts",
  140.                     "cast lightning balls",
  141.                     "cast acid balls",
  142.                     "create traps",
  143.                     "wound %s prey",
  144.                     "cast mind blasting",
  145.                     "teleport away %s prey",
  146.                     "heal",
  147.                     "haste",
  148.                     "fire missiles",
  149.                     "cast plasma bolts",
  150.                     "summon many creatures",
  151.                     "cast nether bolts",
  152.                     "cast ice bolts",
  153.                     "cast darkness",
  154.                     "cause amnesia",
  155.                     "sear your mind",
  156.                     "cast stinking clouds",
  157.                     "teleport %s preys level",
  158.                     "cast water bolts",
  159.                     "cast whirlpools",
  160.                     "cast nether balls",
  161.                     "summon an angel",
  162.                     "summon spiders",
  163.                     "summon hounds",
  164.                     "nexus",    /* part 2... */
  165.                     "elemental force",    /* breaths 3 */
  166.                     "inertia",
  167.                     "light",
  168.                     "time",
  169.                     "gravity",
  170.                     "darkness",
  171.                     "plasma",    /* end */
  172.                     "fire arrows",
  173.                     "summon Ringwraiths",
  174.                     "cast darkness storms",
  175.                     "cast mana storms",
  176.                     "summon reptiles",
  177.                     "summon ants",
  178.                     "summon unique creatures",
  179.                     "summon greater undead",
  180.                     "summon ancient dragons",
  181. };
  182.  
  183. static const char  *desc_weakness[] = {
  184.                        "bright light",
  185.                        "rock remover"
  186. };
  187.  
  188. static const char  *desc_immune[] = {
  189.                      "frost",
  190.                      "fire",
  191.                      "lightning",
  192.                      "poison",
  193.                      "acid"
  194. };
  195.  
  196. static vtype        roffbuf;       /* Line buffer. */
  197. static char        *roffp;       /* Pointer into line buffer. */
  198. static int          roffpline;       /* Place to print line now being loaded. */
  199.  
  200. #define plural(c, ss, sp)    ((c) == 1 ? ss : sp)
  201.  
  202. /* Number of kills needed for information. */
  203.  
  204. /* the higher the level of the monster, the fewer the kills you need */
  205. #define knowarmor(l,d)        ((d) > 304 / (4 + (l)))
  206.  
  207. /* the higher the level of the monster, the fewer the attacks you need, the
  208.  * more damage an attack does, the more attacks you need 
  209.  */
  210. #define knowdamage(l,a,d)    ((4 + (l))*(a) > 80 * (d))
  211.  
  212. /* use slightly different tests for unique monsters to hasten learning -CFT */
  213. #define knowuniqarmor(l,d)    ((d) > 304 / (38 + (5*(l))/4))
  214. #define knowuniqdamage(l,a,d) ((4 +(long)(l))*(2*(long)(a)) > 80 * (d))
  215.  
  216. /* Do we know anything about this monster? */
  217. int 
  218. bool_roff_recall(mon_num)
  219. int mon_num;
  220. {
  221.     register recall_type *mp;
  222.     register int          i;
  223.  
  224.     if (wizard)
  225.     return TRUE;
  226.     mp = &c_recall[mon_num];
  227.     if (mp->r_cmove || mp->r_cdefense || mp->r_kills || mp->r_spells ||
  228.     mp->r_spells2 || mp->r_spells3 || mp->r_deaths)
  229.     return TRUE;
  230.     for (i = 0; i < 4; i++)
  231.     if (mp->r_attacks[i])
  232.         return TRUE;
  233.     return FALSE;
  234. }
  235.  
  236. /* Print out what we have discovered about this monster. */
  237. int 
  238. roff_recall(mon_num)
  239. int mon_num;
  240. {
  241.     const char             *p, *q;
  242.     attid                  *pu;
  243.     vtype                   temp;
  244.     register recall_type   *mp;
  245.     register creature_type *cp;
  246.     register int32u         i, k;   /* changed from int, to avoid PC's 16bit ints -CFT */
  247.     int32u              j;
  248.     int                 mspeed;
  249.     int32u              rcmove, rspells, rspells2, rspells3;
  250.     int32u              rcdefense; /* this was int16u, but c_recall[] uses int32u -CFT */
  251.     recall_type         save_mem;
  252.     int                 breath = FALSE, magic = FALSE;
  253.     char                sex;
  254.  
  255.     cp = &c_list[mon_num];
  256.     sex = cp->gender;
  257.     mp = &c_recall[mon_num];
  258.     if (wizard) {
  259.     save_mem = *mp;
  260.     mp->r_kills = MAX_SHORT;
  261.     mp->r_wake = mp->r_ignore = MAX_UCHAR;
  262.     j = (((cp->cmove & CM_4D2_OBJ) != 0) * 8) +
  263.         (((cp->cmove & CM_2D2_OBJ) != 0) * 4) +
  264.         (((cp->cmove & CM_1D2_OBJ) != 0) * 2) +
  265.         ((cp->cmove & CM_90_RANDOM) != 0) +
  266.         ((cp->cmove & CM_60_RANDOM) != 0);
  267.     mp->r_cmove = (cp->cmove & ~CM_TREASURE) | (j << CM_TR_SHIFT);
  268.     mp->r_cdefense = cp->cdefense;
  269.     mp->r_spells = cp->spells | CS_FREQ;
  270.     mp->r_spells2 = cp->spells2;
  271.     mp->r_spells3 = cp->spells3;
  272.     j = 0;
  273.     pu = cp->damage;
  274.     while (*pu != 0 && j < 4) {
  275.         mp->r_attacks[j] = MAX_UCHAR;
  276.         j++;
  277.         pu++;
  278.     }
  279.     }
  280.     roffpline = 0;
  281.     roffp = roffbuf;
  282.     rspells = mp->r_spells & cp->spells & ~CS_FREQ;
  283.     rspells2 = mp->r_spells2 & cp->spells2;
  284.     rspells3 = mp->r_spells3 & cp->spells3;
  285. /* the CM_WIN property is always known, set it if a win monster */
  286.     rcmove = mp->r_cmove | (CM_WIN & cp->cmove);
  287.     rcdefense = mp->r_cdefense & cp->cdefense;
  288.     if ((cp->cdefense & UNIQUE) || (sex == 'p'))
  289.     (void)sprintf(temp, "%s:\n", cp->name);
  290.     else
  291.     (void)sprintf(temp, "The %s:\n", cp->name);
  292.     roff(temp);
  293. /* Conflict history. */
  294. /* changed to act better for unique monsters -CFT */
  295.     if (cp->cdefense & UNIQUE) {   /* treat unique differently... -CFT */
  296.     if (mp->r_deaths) {       /* We've been killed... */
  297.         (void)sprintf(temp, "%s slain %d of your ancestors",
  298.               (sex == 'm' ? "He has" : sex == 'f' ? "She has" :
  299.                sex == 'p' ? "They have" : "It has"),
  300.               mp->r_deaths);
  301.         roff(temp);
  302.         if (u_list[mon_num].dead) {    /* but we've also killed it */
  303.         sprintf(temp, ", but you have avenged %s!  ",
  304.             plural(mp->r_deaths, "him", "them"));
  305.         roff(temp);
  306.         } else {
  307.         sprintf(temp, ", who %s unavenged.  ",
  308.             plural(mp->r_deaths, "remains", "remain"));
  309.         roff(temp);
  310.         }
  311.     } else if (u_list[mon_num].dead) {    /* we killed it w/o dying...
  312.                          * yet! */
  313.         roff("You have slain this foe.  ");
  314.     }
  315.     } else if (mp->r_deaths) {       /* not unique.... */
  316.     (void)sprintf(temp,
  317.               "%d of your ancestors %s",
  318.               mp->r_deaths, plural(mp->r_deaths, "has", "have"));
  319.     roff(temp);
  320.     roff((sex == 'p' ? " been killed by these creatures, and " :
  321.           " been killed by this creature, and "));
  322.     if (mp->r_kills == 0) {
  323.         sprintf(temp, "%s not ever known to have been defeated.  ",
  324.             (sex == 'm' ? "he is" : sex == 'f' ? "she is"
  325.              : sex == 'p' ? "they are" : "it is"));
  326.         roff(temp);
  327.     } else {
  328.         (void)sprintf(temp,
  329.             "at least %d of the beasts %s been exterminated.  ",
  330.               mp->r_kills, plural(mp->r_kills, "has", "have"));
  331.         roff(temp);
  332.     }
  333.     } else if (mp->r_kills) {
  334.     (void)sprintf(temp, "At least %d of these creatures %s",
  335.               mp->r_kills, plural(mp->r_kills, "has", "have"));
  336.     roff(temp);
  337.     roff(" been killed by you and your ancestors.  ");
  338.     } else
  339.     roff("No battles to the death are recalled.  ");
  340. /* Immediately obvious. */
  341.  
  342. #if 0
  343.     for (k = 0; k < MAX_CREATURES; k++) {
  344.     if (!stricmp(desc_list[k].name, cp->name)) {
  345.         if (strlen(desc_list[k].desc) != 0)
  346.         roff(desc_list[k].desc);
  347.         break;
  348.     }
  349.     }
  350. #endif
  351.     k = mon_num;
  352.     if (k == MAX_CREATURES - 1)
  353.     roff("You feel you know it, and it knows you.  This can only mean trouble.  ");
  354.     else {
  355.     roff(desc_list[k].desc);
  356.     roff("  ");
  357.     }
  358.     k = FALSE;
  359.     if (cp->level == 0) {
  360.     sprintf(temp, "%s in the town",
  361.         (sex == 'm' ? "He lives" : sex == 'f' ? "She lives" :
  362.          sex == 'p' ? "They live" : "It lives"));
  363.     roff(temp);
  364.     k = TRUE;
  365.     } else if (mp->r_kills) {
  366.     (void)sprintf(temp, "%s normally found at depths of %d feet",
  367.               (sex == 'm' ? "He is" : sex == 'f' ? "She is" :
  368.                sex == 'p' ? "They are" : "It is"),
  369.               cp->level * 50);
  370.     roff(temp);
  371.     k = TRUE;
  372.     }
  373. /* the c_list speed value is 10 greater, so that it can be a int8u */
  374.     mspeed = cp->speed - 10;
  375.     if ((rcmove & CM_ALL_MV_FLAGS) || (rcmove & CM_RANDOM_MOVE)) {
  376.     if (k)
  377.         roff(", and");
  378.     else {
  379.         roff((sex == 'm' ? "He" : sex == 'f' ? "She" :
  380.           sex == 'p' ? "They" : "It"));
  381.         k = TRUE;
  382.     }
  383.     roff((sex == 'p' ? " move" : " moves"));
  384.     if (rcmove & CM_RANDOM_MOVE) {
  385.         roff(desc_howmuch[(rcmove & CM_RANDOM_MOVE) >> 3]);
  386.         roff(" erratically");
  387.     }
  388.     if (mspeed == 1)
  389.         roff(" at normal speed");
  390.     else {
  391.         if (rcmove & CM_RANDOM_MOVE)
  392.         roff(", and");
  393.         if (mspeed <= 0) {
  394.         if (mspeed == -1)
  395.             roff(" very");
  396.         else if (mspeed < -1)
  397.             roff(" incredibly");
  398.         roff(" slowly");
  399.         } else {
  400.         if (mspeed == 3)
  401.             roff(" very");
  402.         else if (mspeed > 3)
  403.             roff(" unbelievably");
  404.         roff(" quickly");
  405.         }
  406.     }
  407.     }
  408.     if (rcmove & CM_ATTACK_ONLY) {
  409.     if (k)
  410.         roff(", but");
  411.     else {
  412.         roff((sex == 'm' ? "He" : sex == 'f' ? "She" :
  413.           sex == 'p' ? "They" : "It"));
  414.         k = TRUE;
  415.     }
  416.     roff(" does not deign to chase intruders");
  417.     }
  418.     if (k)
  419.     roff(".  ");
  420. /* Kill it once to know experience, and quality (evil, undead, monsterous).
  421.  * The quality of being a dragon is obvious. 
  422.  */
  423.     if (mp->r_kills) {
  424.     if (cp->cdefense & UNIQUE)
  425.         roff("Killing this");
  426.     else
  427.         roff((sex == 'p' ? "A kill of these" : "A kill of this"));
  428.  
  429.     if (cp->cdefense & ANIMAL)
  430.         roff(" natural");
  431.     if (cp->cdefense & EVIL)
  432.         roff(" evil");
  433.     if (cp->cdefense & UNDEAD)
  434.         roff(" undead");
  435.  
  436.     if (cp->cdefense & GIANT)
  437.         roff(" giant");
  438.     else if (cp->cdefense & ORC)
  439.         roff(" orc");
  440.     else if (cp->cdefense & DRAGON)
  441.         roff(" dragon");
  442.     else if (cp->cdefense & DEMON)
  443.         roff(" demon");
  444.     else if (cp->cdefense & TROLL)
  445.         roff(" troll");
  446.     else
  447.         roff((sex == 'p' ? " creatures" : " creature"));
  448.  
  449.     /* calculate the integer exp part */
  450.     i = (long)cp->mexp * cp->level / py.misc.lev;
  451.  
  452.     /* calculate the fractional exp part scaled by 100, must use long
  453.      * arithmetic to avoid overflow 
  454.      */
  455.     j = (((long)cp->mexp * cp->level % py.misc.lev) * (long)1000 /
  456.          py.misc.lev + 5) / 10;
  457.  
  458.     (void)sprintf(temp, " is worth %lu.%02lu point%s", i,
  459.               (unsigned long)j, (unsigned long)(i == 1 && j == 0 ? "" : "s"));
  460.     roff(temp);
  461.  
  462.     if ((py.misc.lev / 10) == 1)
  463.         p = "th";
  464.     else {
  465.         i = py.misc.lev % 10;
  466.         if (i == 1)
  467.         p = "st";
  468.         else if (i == 2)
  469.         p = "nd";
  470.         else if (i == 3)
  471.         p = "rd";
  472.         else
  473.         p = "th";
  474.     }
  475.     i = py.misc.lev;
  476.     if ((i == 8) || (i == 11) || (i == 18))
  477.         q = "n";
  478.     else
  479.         q = "";
  480.     (void)sprintf(temp, " for a%s %lu%s level character.  ", q, (long)i, p);
  481.     roff(temp);
  482.     if (cp->cdefense & GROUP) {
  483.         sprintf(temp, "%s usually appears in groups.  ",
  484.             (sex == 'm' ? "He" : sex == 'f' ? "She" :
  485.              sex == 'p' ? "They" : "It"));
  486.         roff(temp);
  487.     }
  488.     }
  489. /* Spells known, if have been used against us. */
  490.     k = TRUE;
  491.     i = 0;
  492.     if ((rspells & CS_BREATHE) || (rspells2 & CS_BREATHE2) ||
  493.     (rspells3 & CS_BREATHE3)) {
  494.     breath = TRUE;
  495.     j = rspells & CS_BREATHE;
  496.     rspells &= ~CS_BREATHE;
  497.     while ((i = bit_pos(&j)) != -1) {
  498.         if (k) {
  499.         sprintf(temp, "%s can breathe ",
  500.             (sex == 'm' ? "He" : sex == 'f' ? "She" :
  501.              sex == 'p' ? "They" : "It"));
  502.         roff(temp);
  503.         k = FALSE;
  504.         } else if (j || (rspells2 & CS_BREATHE2) || (rspells3 & CS_BREATHE3))
  505.         roff(", ");
  506.         else
  507.         roff(" and ");
  508.         sprintf(temp, desc_spell[i],
  509.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  510.              sex == 'p' ? "their" : "its"));
  511.         roff(temp);
  512.     }
  513.     j = rspells2 & CS_BREATHE2;
  514.     rspells2 &= ~CS_BREATHE2;
  515.     while ((i = bit_pos(&j)) != -1) {
  516.         if (k) {
  517.         sprintf(temp, "%s can breathe ",
  518.             (sex == 'm' ? "He" : sex == 'f' ? "She" :
  519.              sex == 'p' ? "They" : "It"));
  520.         roff(temp);
  521.         k = FALSE;
  522.         } else if (j || (rspells3 & CS_BREATHE3))
  523.         roff(", ");
  524.         else
  525.         roff(" and ");
  526.         sprintf(temp, desc_spell[i + 32],
  527.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  528.              sex == 'p' ? "their" : "its"));
  529.         roff(temp);
  530.     }
  531.     j = rspells3 & CS_BREATHE3;
  532.     rspells &= ~CS_BREATHE3;
  533.     while ((i = bit_pos(&j)) != -1) {
  534.         if (k) {
  535.         sprintf(temp, "%s can breathe ",
  536.             (sex == 'm' ? "He" : sex == 'f' ? "She" :
  537.              sex == 'p' ? "They" : "It"));
  538.         roff(temp);
  539.         k = FALSE;
  540.         } else if (j)
  541.         roff(", ");
  542.         else
  543.         roff(" and ");
  544.         sprintf(temp, desc_spell[i + 64],
  545.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  546.              sex == 'p' ? "their" : "its"));
  547.         roff(temp);
  548.     }
  549.     }
  550.     k = TRUE;
  551.     if (rspells || rspells2 || rspells3) {
  552.     magic = TRUE;
  553.     j = rspells & ~CS_BREATHE;
  554.     while ((i = bit_pos(&j)) != -1) {
  555.         if (k) {
  556.         if (breath)
  557.             roff((sex == 'p' ? ", and are also" : ", and is also"));
  558.         else
  559.             roff((sex == 'm' ? "He is" : sex == 'f' ? "She is" :
  560.               sex == 'p' ? "They are" : "It is"));
  561.         if (mp->r_cdefense & INTELLIGENT)
  562.             roff(" magical, casting spells intelligently which ");
  563.         else
  564.             roff(" magical, casting spells which ");
  565.         k = FALSE;
  566.         } else if ((j & CS_SPELLS) || rspells2 || rspells3)
  567.         roff(", ");
  568.         else
  569.         roff(" or ");
  570.         sprintf(temp, desc_spell[i],
  571.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  572.              sex == 'p' ? "their" : "its"));
  573.         roff(temp);
  574.     }
  575.     j = rspells2 & ~CS_BREATHE2;
  576.     while ((i = bit_pos(&j)) != -1) {
  577.         if (k) {
  578.         if (breath)
  579.             roff((sex == 'p' ? ", and are also" : ", and is also"));
  580.         else
  581.             roff((sex == 'm' ? "He is" : sex == 'f' ? "She is" :
  582.               sex == 'p' ? "They are" : "It is"));
  583.         roff(" magical, casting spells which ");
  584.         k = FALSE;
  585.         } else if (j || rspells3)
  586.         roff(", ");
  587.         else
  588.         roff(" or ");
  589.         sprintf(temp, desc_spell[i + 32],
  590.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  591.              sex == 'p' ? "their" : "its"));
  592.         roff(temp);
  593.     }
  594.     j = rspells3 & ~CS_BREATHE3;
  595.     while ((i = bit_pos(&j)) != -1) {
  596.         if (k) {
  597.         if (breath)
  598.             roff((sex == 'p' ? ", and are also" : ", and is also"));
  599.         else
  600.             roff((sex == 'm' ? "He is" : sex == 'f' ? "She is" :
  601.               sex == 'p' ? "They are" : "It is"));
  602.         roff(" magical, casting spells which ");
  603.         k = FALSE;
  604.         } else if (j)
  605.         roff(", ");
  606.         else
  607.         roff(" or ");
  608.         sprintf(temp, desc_spell[i + 64],
  609.             (sex == 'm' ? "his" : sex == 'f' ? "her" :
  610.              sex == 'p' ? "their" : "its"));
  611.         roff(temp);
  612.     }
  613.     }
  614.     if (breath || magic) {
  615.     if ((mp->r_spells & CS_FREQ) > 5) {    /* Could offset by level */
  616.         (void)sprintf(temp, "; 1 time in %lu", cp->spells & CS_FREQ);
  617.         roff(temp);
  618.     }
  619.     roff(".  ");
  620.     }
  621.  
  622. /* Do we know how hard they are to kill? Armor class, hit die. */
  623.     if (knowarmor(cp->level, mp->r_kills) ||    /* hasten learning of uniques -CFT */
  624.     ((cp->cdefense & UNIQUE) && knowuniqarmor(cp->level, mp->r_kills))) {
  625.     (void)sprintf(temp, "%s an armor rating of %d",
  626.               (sex == 'm' ? "He has" : sex == 'f' ? "She has" :
  627.                sex == 'p' ? "They have" : "It has"),
  628.               cp->ac);
  629.     roff(temp);
  630.     (void)sprintf(temp, " and a%s life rating of %dd%d.  ",
  631.               ((cp->cdefense & MAX_HP) ? " maximized" : ""),
  632.               cp->hd[0], cp->hd[1]);
  633.     roff(temp);
  634.     }
  635. /* Do we know how clever they are? Special abilities. */
  636.     k = TRUE;
  637.     j = rcmove;
  638.     if (rcdefense & BREAK_WALL) {  /* I wonder why this wasn't here before? -CFT */
  639.     roff((sex == 'm' ? "He can bore through rock" :
  640.           sex == 'f' ? "She can bore through rock" :
  641.           sex == 'p' ? "They can bore through rock" :
  642.           "It can bore through rock"));
  643.     k = FALSE;
  644.     }
  645.     for (i = 0; j & CM_SPECIAL; i++) {
  646.     if (j & (CM_INVISIBLE << i)) {
  647.         j &= ~(CM_INVISIBLE << i);
  648.         if (k) {
  649.         roff((sex == 'm' ? "He can " : sex == 'f' ? "She can " :
  650.               sex == 'p' ? "They can " : "It can "));
  651.         k = FALSE;
  652.         } else if (j & CM_SPECIAL)
  653.         roff(", ");
  654.         else
  655.         roff(" and ");
  656.         roff(desc_move[i]);
  657.     }
  658.     }
  659.     if (!k)
  660.     roff(".  ");
  661. /* Do we know its special weaknesses? Most cdefense flags. */
  662.     k = TRUE;
  663.     j = rcdefense;
  664.     if (j & HURT_LIGHT) {
  665.     if (k) {
  666.         roff((sex == 'm' ? "He is susceptible to " :
  667.           sex == 'f' ? "She is susceptible to " :
  668.           sex == 'p' ? "They are susceptible to " :
  669.           "It is susceptible to "));
  670.         roff(desc_weakness[0]);
  671.         k = FALSE;
  672.     }
  673.     }
  674.     if (j & HURT_ROCK) {
  675.     if (k) {
  676.         roff((sex == 'm' ? "He is susceptible to " :
  677.           sex == 'f' ? "She is susceptible to " :
  678.           sex == 'p' ? "They are susceptible to " :
  679.           "It is susceptible to "));
  680.         roff(desc_weakness[1]);
  681.         k = FALSE;
  682.     } else {
  683.         roff(" and ");
  684.         roff(desc_weakness[1]);
  685.     }
  686.     }
  687.     if (!k)
  688.     roff(".  ");
  689. /* Do we know its special weaknesses? Most cdefense flags. */
  690.     k = TRUE;
  691.     for (i = 0; j & (IM_FROST | IM_FIRE | IM_ACID | IM_POISON | IM_LIGHTNING); i++) {
  692.     if (j & (IM_FROST << i)) {
  693.         j &= ~(IM_FROST << i);
  694.         if (k) {
  695.         roff((sex == 'm' ? "He resists " :
  696.               sex == 'f' ? "She resists " :
  697.               sex == 'p' ? "They resist " :
  698.               "It resists "));
  699.         k = FALSE;
  700.         } else if (j & (IM_FROST | IM_FIRE | IM_ACID | IM_POISON | IM_LIGHTNING))
  701.         roff(", ");
  702.         else
  703.         roff(" and ");
  704.         roff(desc_immune[i]);
  705.     }
  706.     }
  707.     if (!k)
  708.     roff(".  ");
  709.     if (rcdefense & NO_INFRA)
  710.     roff((sex == 'm' ? "He is cold blooded" :
  711.           sex == 'f' ? "She is cold blooded" :
  712.           sex == 'p' ? "They are cold blooded" :
  713.           "It is cold blooded"));
  714.     if (rcdefense & CHARM_SLEEP) {
  715.     if (rcdefense & NO_INFRA)
  716.         roff(", and");
  717.     else
  718.         roff((sex == 'm' ? "He" : sex == 'f' ? "She" :
  719.           sex == 'p' ? "They" : "It"));
  720.     roff(" cannot be charmed or slept");
  721.     }
  722.     if (rcdefense & (CHARM_SLEEP | NO_INFRA))
  723.     roff(".  ");
  724. /* Do we know how aware it is? */
  725.     if (((mp->r_wake * mp->r_wake) > cp->sleep) || mp->r_ignore == MAX_UCHAR ||
  726.     (cp->sleep == 0 && mp->r_kills >= 10)) {
  727.     roff((sex == 'm' ? "He " : sex == 'f' ? "She " :
  728.           sex == 'p' ? "They " : "It "));
  729.     if (cp->sleep > 200)
  730.         roff("prefers to ignore");
  731.     else if (cp->sleep > 95)
  732.         roff("pays very little attention to");
  733.     else if (cp->sleep > 75)
  734.         roff("pays little attention to");
  735.     else if (cp->sleep > 45)
  736.         roff("tends to overlook");
  737.     else if (cp->sleep > 25)
  738.         roff("takes quite a while to see");
  739.     else if (cp->sleep > 10)
  740.         roff("takes a while to see");
  741.     else if (cp->sleep > 5)
  742.         roff((sex == 'p' ? "are fairly observant of" : "is fairly observant of"));
  743.     else if (cp->sleep > 3)
  744.         roff((sex == 'p' ? "are observant of" : "is observant of"));
  745.     else if (cp->sleep > 1)
  746.         roff((sex == 'p' ? "are very observant of" : "is very observant of"));
  747.     else if (cp->sleep != 0)
  748.         roff((sex == 'p' ? "are vigilant for" : "is vigilant for"));
  749.     else
  750.         roff((sex == 'p' ? "are ever vigilant for" : "is ever vigilant for"));
  751.     (void)sprintf(temp, " intruders, which %s may notice from %d feet.  ",
  752.               (sex == 'm' ? "he" : sex == 'f' ? "she" :
  753.                sex == 'p' ? "they" : "it"),
  754.               10 * cp->aaf);
  755.     roff(temp);
  756.     }
  757. /* Do we know what it might carry? */
  758.     if (rcmove & (CM_CARRY_OBJ | CM_CARRY_GOLD)) {
  759.     roff((sex == 'm' ? "He may" : sex == 'f' ? "She may" :
  760.           sex == 'p' ? "They may" : "It may"));
  761.     j = (rcmove & CM_TREASURE) >> CM_TR_SHIFT;
  762.     if (j == 1) {
  763.         if ((cp->cmove & CM_TREASURE) == CM_60_RANDOM)
  764.         roff(" sometimes");
  765.         else
  766.         roff(" often");
  767.     } else if ((j == 2) && ((cp->cmove & CM_TREASURE) ==
  768.                 (CM_60_RANDOM | CM_90_RANDOM)))
  769.         roff(" often");
  770.     roff(" carry");
  771.     if (cp->cdefense & SPECIAL) /* it'll tell you who has better treasure -CFT */
  772.         p = (j==1?"n exceptional object":" exceptional objects");
  773.     else if (cp->cdefense & GOOD)
  774.         p = (j==1?" good object":" good objects");
  775.     else
  776.         p = (j==1?"n object":" objects");
  777.     if (j == 1)
  778.         p = " an object";
  779.     else if (j == 2)
  780.         roff(" one or two");
  781.     else {
  782.         (void)sprintf(temp, " up to %lu", (long)j);
  783.         roff(temp);
  784.     }
  785.     if (rcmove & CM_CARRY_OBJ) {
  786.         roff(p);
  787.         if (rcmove & CM_CARRY_GOLD) {
  788.         roff(" or treasure");
  789.         if (j > 1)
  790.             roff("s");
  791.         }
  792.         roff(".  ");
  793.     } else if (j != 1)
  794.         roff(" treasures.  ");
  795.     else
  796.         roff(" treasure.  ");
  797.     }
  798.  
  799. /* We know about attacks it has used on us, and maybe the damage they do. */
  800. /* k is the total number of known attacks, used for punctuation */
  801.     k = 0;
  802.     for (j = 0; j < 4; j++)
  803.     if (mp->r_attacks[j])
  804.         k++;
  805.     pu = cp->damage;
  806. /* j counts the attacks as printed, used for punctuation */
  807.     j = 0;
  808.     for (i = 0; *pu != 0 && i < 4; pu++, i++) {
  809.     int                 att_type, att_how, d1, d2;
  810.  
  811.     /* don't print out unknown attacks */
  812.     if (!mp->r_attacks[i])
  813.         continue;
  814.  
  815.     att_type = monster_attacks[*pu].attack_type;
  816.     att_how = monster_attacks[*pu].attack_desc;
  817.     d1 = monster_attacks[*pu].attack_dice;
  818.     d2 = monster_attacks[*pu].attack_sides;
  819.  
  820.     j++;
  821.     if (j == 1)
  822.         roff((sex == 'm' ? "He can " : sex == 'f' ? "She can " :
  823.           sex == 'p' ? "They can " : "It can "));
  824.     else if (j == k)
  825.         roff(", and ");
  826.     else
  827.         roff(", ");
  828.  
  829.     if (att_how > 23)
  830.         att_how = 0;
  831.     roff(desc_amethod[att_how]);
  832.     if (att_type != 1 || (d1 > 0 && d2 > 0)) {
  833.         roff(" to ");
  834.         if (att_type > 25)
  835.         att_type = 0;
  836.         roff(desc_atype[att_type]);
  837.         if (d1 && d2) {
  838.         if (knowdamage(cp->level, mp->r_attacks[i], (int)d1 * (int)d2) ||
  839.             ((cp->cdefense & UNIQUE) &&    /* learn uniques faster -CFT */
  840.              knowuniqdamage(cp->level, mp->r_attacks[i], (int)d1 * (int)d2))) {
  841.             if (att_type == 19)    /* Loss of experience */
  842.             roff(" by");
  843.             else
  844.             roff(" with damage");
  845.             (void)sprintf(temp, " %dd%d", d1, d2);
  846.             roff(temp);
  847.         }
  848.         }
  849.     }
  850.     }
  851.     if (j)
  852.     roff(".");
  853.     else if (k > 0 && mp->r_attacks[0] >= 10) {
  854.     sprintf(temp, " %s no physical attacks.",
  855.         (sex == 'm' ? "He has" : sex == 'f' ? "She has" :
  856.          sex == 'p' ? "They have" : "It has"));
  857.     roff(temp);
  858.     } else {
  859.     sprintf(temp, "Nothing is known about %s attack.",
  860.         (sex == 'm' ? "his" : sex == 'f' ? "her" :
  861.          sex == 'p' ? "their" : "its"));
  862.     roff(temp);
  863.     }
  864. /* Always know the win creature. */
  865.     if (cp->cmove & CM_WIN)
  866.     roff("  Killing him wins the game!");
  867.     roff("\n");
  868.     prt("   --pause--", roffpline, 0);
  869.     if (wizard)
  870.     *mp = save_mem;
  871.     return inkey();
  872. }
  873.  
  874. /* Print out strings, filling up lines as we go. */
  875. static void 
  876. roff(p)
  877. register const char *p;
  878. {
  879.     register char *q, *r;
  880.     register int   linesize;
  881.  
  882.     linesize = sizeof(roffbuf);
  883.     if (linesize > 80)
  884.     linesize = 80;
  885.  
  886.     while (*p) {
  887.     *roffp = *p;
  888.     if (*p == '\n' || roffp >= roffbuf + linesize) {
  889.         q = roffp;
  890.         if (*p != '\n') {
  891.         if (*q == ' ')
  892.             q--;
  893.         if (*q == ' ')
  894.             q--;
  895.         while (*q != ' ')
  896.             q--;
  897.         }
  898.         *q = 0;
  899.         prt(roffbuf, roffpline, 0);
  900.         roffpline++;
  901.         r = roffbuf;
  902.         while (q < roffp)
  903.         *r++ = *++q;
  904.         roffp = r;
  905.     } else
  906.         roffp++;
  907.     p++;
  908.     }
  909. }
  910.